#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include "fix.h"

int dumpMemory(int pid, uint64_t begin, uint64_t end, const char *outPath);

static const char *_sandardlizeAddrs(char *buf, const char *addr) {
  if (addr[0] != '0' || addr[1] != 'x') {
    sprintf(buf, "0x%s", addr);
    return buf;
  } else {
    return addr;
  }
}

static int __main(int argc, char *argv[]) {
  if (argc < 5) {
    printf(logprefix "Dump_Fix ~ " 
        "%s <pid> <base_hex> <end_hex> <outPath> [is-stop-process-before-dump] "
        "[is-fix-so-after-dump]\n",
        argv[0]);
    return -1;
  }

  long pid = strtol(argv[1], 0, 10);
  uint64_t begin = 0, end = 0;
  char bufBegin[255] = {0};
  const char *strBegin = _sandardlizeAddrs(bufBegin, argv[2]);

  begin = strtoull(strBegin, 0, 16);

  char bufEnd[255] = {0};
  const char *strEnd = _sandardlizeAddrs(bufEnd, argv[3]);

  end = strtoull(strEnd, 0, 16);

  const char *outPath = argv[4];
  char tmpPath[255] = {0};
  sprintf(tmpPath, "%s.tmp", outPath);

  bool stopBeforeDump = false;
  if (argc > 5) {
    stopBeforeDump = argv[5][0] != '0';
  }
  if (pid != 0 && stopBeforeDump) {
    printf(logprefix "Dump_Fix ~ " "stop process %ld before dump\n", pid);
    kill(pid, SIGSTOP);
  }
  int res = dumpMemory(pid, begin, end, tmpPath);
  if (res < 0) {
    printf(logprefix "Dump_Fix ~ " "error dumpMemory return %d, did you run in root, did pid exist?\n",
           res);
    return res;
  }
  if (pid != 0 && stopBeforeDump) {
    printf(logprefix "Dump_Fix ~ " "resume process %ld after dump\n", pid);
    kill(pid, SIGCONT);
  }
  chmod(tmpPath, 0666);
  bool isFixSo = true;
  if (argc > 6) {
    isFixSo = argv[6][0] != '0';
  }

  if (isFixSo) {
    printf(logprefix "Dump_Fix ~ " "try fix %s\n", tmpPath);
    fix_so(tmpPath, outPath, (unsigned)begin);
    printf(logprefix "Dump_Fix ~ " "end fix %s output to %s\n", tmpPath, outPath);
    chmod(outPath, 0666);
  } else {
    rename(tmpPath, outPath);
  }

  return 0;
}

int main(int argc, char *argv[]) { return __main(argc, argv); }
